﻿using DataType.CustomEnumType;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;

namespace DataType
{
    public class ShootJudgeTable
    {
        /// <summary>
        /// 从文件中读取数据，赋值给私有字段
        /// </summary>
        /// <param name="Path"></param>
        public ShootJudgeTable(string path)
        {
            // 根据xml文件初始化weapons，每个xml文件对应一个weapon
            string weaponPath = path + @"\weapons\";
            string[] weaponFiles = Directory.GetFiles(weaponPath, "*.xml", SearchOption.TopDirectoryOnly);  // 只在本级路径中搜索文件

            foreach (string weaponFile in weaponFiles)
            {
                Weapon weapon = GetWeaponFromFile(weaponFile);
                weapons.Add(weapon.Name, weapon);
            }

            // 根据Json文件初始化elevRectTab表格
            string elevRectTabString = File.ReadAllText(Path.Combine(path, "elev_rect_tab.json"));
            elevRectTab = JsonConvert.DeserializeObject<int[,]>(elevRectTabString);

            // 根据Json文件初始化attackLevel2OriDamageTab表格
            string attackLevel2OriDamageTabString = File.ReadAllText(Path.Combine(path, "attack_level_2_ori_damage_tab.json"));
            attackLevel2OriDamageTab = JsonConvert.DeserializeObject<int[,]>(attackLevel2OriDamageTabString);

            // 根据Json文件初始化originDamageTab表格
            string originDamageTabString = File.ReadAllText(Path.Combine(path, "origin_damage_tab.json"));
            originDamageTab = JsonConvert.DeserializeObject<int[,]>(originDamageTabString);

            // 根据Json文件初始化damageRectTab表格
            string damageRectTabString = File.ReadAllText(Path.Combine(path, "damage_rect_tab.json"));
            damageRectTab = JsonConvert.DeserializeObject<int[,]>(damageRectTabString);

            // 根据Json文件初始化toInfantryOriDamageTab表格
            string toInfantryOriDamageTabString = File.ReadAllText(Path.Combine(path, "to_infantry_ori_damage_tab.json"));
            toInfantryOriDamageTab = JsonConvert.DeserializeObject<int[,]>(toInfantryOriDamageTabString);

            // 根据Json文件初始化toInfantryDamageRectTab表格
            string toInfantryDamageRectTabString = File.ReadAllText(Path.Combine(path, "to_infantry_damage_rect_tab.json"));
            toInfantryDamageRectTab = JsonConvert.DeserializeObject<int[]>(toInfantryDamageRectTabString);
        }

        private Dictionary<WeaponType, Weapon> weapons = new Dictionary<WeaponType, Weapon>();
        private int[,] elevRectTab;
        /*    1   2   3   4   5   6   7   8   9  10  11  12 --> Distance  
         *  {-2, -2, -1, -1, -1,  0,  0,  0,  0,  0,  0,  0, },  1\
            {-2, -2, -2, -1, -1, -1, -1,  0,  0,  0,  0,  0, },  2 \
            {-3, -2, -2, -2, -1, -1, -1, -1, -1,  0,  0,  0, },  3  \
            {-3, -3, -3, -2, -2, -1, -1, -1, -1, -1, -1,  0, },  4   \ 高度差
            {-4, -3, -3, -3, -2, -2, -2, -1, -1, -1, -1, -1, },  5   / elev_diff
            {-4, -4, -4, -3, -3, -2, -2, -2, -1, -1, -1, -1, },  6  /
            {-5, -4, -4, -4, -3, -2, -2, -2, -2, -1, -1, -1, },  7 /
            {-5, -5, -5, -4, -3, -3, -2, -2, -2, -2, -2, -1, }   8/
         */
        private int[,] attackLevel2OriDamageTab;
        /*   1, 2, 3, 4,  5,  6,  7,  8, 9,  10  --> attack level
            {0, 2, 3, 4,  5,  6,  7,  8, 10, 11 },  // 1 \
            {1, 3, 5, 6,  7,  8,  9, 11, 12, 13 },  // 2  \
            {2, 4, 6, 7,  9, 11, 12, 13, 14, 15 },  // 3   } blood
            {2, 4, 6, 8, 10, 12, 13, 14, 16, 17 },  // 4  /
            {2, 4, 8,10, 13, 14, 15, 17, 18, 19 }   // 5 /
            此表中的值，对应了下面表originDamageTab中的行数，0->第0行，……，19->第19行
         */
        private int[,] originDamageTab;
        /*   2, 3, 4, 5, 6, 7, 8, 9,10,11,12  -> 两个骰子的点数之和
            {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
            {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
            {0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 },
            {0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0 },
            {0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0 },
            {0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0 },
            {1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0 },
            {1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0 },
            {1, 0, 1, 1, 1, 2, 1, 0, 0, 0, 0 },
            {1, 1, 1, 1, 1, 2, 1, 1, 0, 0, 0 },
            {1, 1, 1, 1, 1, 2, 0, 2, 0, 2, 0 },
            {1, 1, 1, 1, 1, 2, 0, 2, 1, 2, 0 },
            {1, 1, 1, 1, 1, 2, 2, 2, 2, 0, 0 },
            {1, 1, 1, 1, 1, 3, 2, 2, 2, 0, 1 },
            {2, 2, 1, 1, 1, 3, 2, 2, 2, 2, 2 },
            {3, 3, 1, 1, 1, 3, 2, 2, 2, 3, 3 },
            {3, 3, 1, 1, 1, 4, 2, 2, 2, 3, 3 },
            {2, 2, 1, 1, 1, 3, 4, 4, 4, 2, 3 },
            {3, 1, 1, 1, 3, 4, 4, 3, 4, 2, 2 },
            {5, 1, 1, 1, 5, 3, 4, 4, 4, 3, 4 }
         */
        private int[,] damageRectTab;
        /*    <=-3 -2  -1   0   1   2   3   4   5   6   7   8   9  10  11  >=12  ->修正后的随机数
            {   0,  0,  0,  0,  0,  0,  1,  1,  1,  1,  1,  1,  1,  2,  2,  3 }, // 无装甲
            {  -1,  0,  0,  0,  0,  0,  0,  0,  0,  1,  1,  1,  1,  2,  2,  3 }, // 轻型装甲
            {  -2, -1, -1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  1,  2,  3 }, // 中型装甲
            {  -3, -2, -2, -1, -1,  0,  0,  0,  0,  0,  0,  0,  0,  1,  2,  2 }, // 重型装甲
            {  -3, -3, -3, -3, -2, -2, -1, -1, -1,  0,  0,  0,  0,  0,  1,  2 }, // 复合装甲
         */
        private int[,] toInfantryOriDamageTab;
        private int[] toInfantryDamageRectTab;

        public Weapon GetWeapon(WeaponType weaponType)
        {
            if (weapons.Keys.Contains(weaponType))
            {
                return weapons[weaponType];
            }
            else
            {
                Trace.TraceError("输入的武器编号不在裁决表中");
                return null;
            }
        }

        public int CalcAttackLevel(bool can_see, Dictionary<BulletType, int> remain_bullet_nums, WeaponType weapon_id, OprType targetType, int distance, int opr_blood = 4)
        {
            if (!can_see) return -1;  // 不可视，即不可射
            Weapon weapon = GetWeapon(weapon_id);
            if (weapon == null) return -1;  // 无此武器的裁决方法
            if (remain_bullet_nums[weapon.Bullet] <= 0) return -1;  // 没有弹药了
            return weapon.GetAttackLevel(targetType, distance, opr_blood);
        }

        public int GetElevRect(int elevDiff, int distance)
        {
            if (elevDiff <= 0) return 0;
            if (distance <= 0) return 0;
            if (distance > 12) return 0;
            if (elevDiff > 8) elevDiff = 8;
            return elevRectTab[elevDiff - 1, distance - 1];  // 数组从0开始计数
        }

        public int GetOriDamageTabRow(int blood, int attackLevel)
        {
            if (blood <= 0) blood = 1;
            if (blood > 5) blood = 5;
            if (attackLevel <= 0)   // 出错
            {
                Trace.TraceError("攻击等级Attack Level计算有误，必须大于0！");
                return -1;
            }
            if (attackLevel > 10) attackLevel = 10;
            return attackLevel2OriDamageTab[blood - 1, attackLevel - 1];  // 数组从0开始计数
        }

        public int GetOriDamage(int oriDamageTabRow, int randomValue)
        {
            if (oriDamageTabRow<0 || oriDamageTabRow > 19)
            {
                Trace.TraceError("输入行数超出了战斗结果表Origin Damage Table的行数");
                return -1;
            }
            if (randomValue < 2) randomValue = 2;
            if (randomValue > 12) randomValue = 12;
            return originDamageTab[oriDamageTabRow, randomValue - 2];
        }

        public int GetDamageRect(ArmorType armor, int randomRect)
        {
            if (randomRect < -3) randomRect = -3;
            if (randomRect > 12) randomRect = 12;
            return damageRectTab[(int)armor, randomRect + 3];
        }

        /// <summary>
        /// 直瞄武器对人员/步兵轻武器对车辆战斗结果表
        /// </summary>
        public int GetToInfantryOriDamageTab(int randomValue, int attackLevel)
        {
            if (attackLevel <= 0)   // 出错
            {
                Trace.TraceError("攻击等级Attack Level计算有误，必须大于0！");
                return -1;
            }
            if (attackLevel > 10) attackLevel = 10;
            return toInfantryOriDamageTab[randomValue - 2, attackLevel - 1];  // 数组从0开始计数
        }

        public int GetToInfantryDamageRect(int randomRect)
        {
            if (randomRect < 0) randomRect = 0;
            if (randomRect > 8) randomRect = 8;
            return toInfantryDamageRectTab[randomRect];
        }

        private Weapon GetWeaponFromFile(string file)
        {
            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.Load(file);

            XmlNodeList classNodes = xmlDoc.SelectNodes("class");

            if (classNodes.Count > 0)
            {
                XmlNode classNode = classNodes[0];
                if (!Enum.TryParse<WeaponType>(classNode["name"].InnerText, out WeaponType weaponName))
                {
                    throw new Exception($"武器文件{file}中缺少武器名称，或者武器名称有误");
                }
                if (!Enum.TryParse<BulletType>(classNode["bullet"].InnerText, out BulletType bullet))
                {
                    throw new Exception($"武器文件{file}中缺少弹药信息，或者弹药名称有误");
                }

                int rangeVehicle = -1;
                //int[] attackLevelsVehicle = null;
                Dictionary<int, int[]> attackLevelsVehicle = null;
                int rangeInfantry = -1;
                Dictionary<int, int[]> attackLevelsInfantry = null;
                //Dictionary<int, int[]> attackLevelsVehicleOfInfantryLightWeapon = null;

                XmlNodeList fieldNodes = xmlDoc.SelectNodes("/class/field");
                foreach (XmlNode field in fieldNodes)
                {
                    switch (field["identifier"].InnerText)
                    {
                        case "rangeVehicle":
                            rangeVehicle = int.Parse(field["value"].InnerText);
                            break;
                        case "attackLevelsVehicle":
                            //if (weaponName == WeaponType.InfantryLightWeapon)//车载轻武器对车辆是字典类型
                            //{
                            //    attackLevelsVehicleOfInfantryLightWeapon = new Dictionary<int, int[]>();
                            //    string[] allValuesOfInfantryLightWeapon = field["value"].InnerText.Split(';');
                            //    for (int i = 0; i < allValuesOfInfantryLightWeapon.Length; i++)
                            //    {
                            //        attackLevelsVehicleOfInfantryLightWeapon[i + 1] = Array.ConvertAll(allValuesOfInfantryLightWeapon[i].Split(','), int.Parse);
                            //    }
                            //}
                            //else
                            //{
                            //    attackLevelsVehicle = Array.ConvertAll(field["value"].InnerText.Split(new char[] { ',' }), int.Parse);
                            //}
                            attackLevelsVehicle = new Dictionary<int, int[]>();
                            string[] allValue = field["value"].InnerText.Split(';');
                            for (int i = 0; i < allValue.Length; i++)
                            {
                                attackLevelsVehicle[i + 1] = Array.ConvertAll(allValue[i].Split(','), int.Parse);
                            }
                            break;
                        case "rangeInfantry":
                            rangeInfantry = int.Parse(field["value"].InnerText);
                            break;
                        case "attackLevelsInfantry":
                            attackLevelsInfantry = new Dictionary<int, int[]>();
                            string[] allValues = field["value"].InnerText.Split(';');
                            for (int i = 0; i < allValues.Length; i++)
                            {
                                attackLevelsInfantry[i + 1] = Array.ConvertAll(allValues[i].Split(','), int.Parse);
                            }
                            break;
                    }
                }

                //if (weaponName == WeaponType.InfantryLightWeapon)
                //    return new Weapon(weaponName, bullet, rangeVehicle, attackLevelsVehicleOfInfantryLightWeapon, rangeInfantry, attackLevelsInfantry);
                //else
                return new Weapon(weaponName, bullet, rangeVehicle, attackLevelsVehicle, rangeInfantry, attackLevelsInfantry);
            }
            else
            {
                throw new Exception($"武器文件{file}格式有错误，根节点应该是class!");
            }
        }
    }
}
